using System;
using System.Collections.Generic;
using SimpleJSON;

namespace Gj
{
    public class CacheTools
    {
        public static Action<string, object> cb;

        public static void RegisterCb(Action<string, object> action)
        {
            cb = action;
        }

        public static void GetData(string key, int time, Action<Action<object[]>> get, Action<object[]> cb)
        {
            var obj = GetData(key);
            if (obj == null)
                get(_obj =>
                {
                    if (_obj != null) SetData(key, time, _obj);
                    cb(_obj);
                });
            else
                cb(obj);
        }

        public static void GetData(string key, Action<int, Action<object[]>> get, Action<object[]> cb,
            Func<object[], object[], bool> compare)
        {
            var obj = GetVal(key);
            var updateTime = 0;
            var arr = new object[0];
            if (obj != null)
            {
                arr = (object[])obj[0];
                updateTime = (int)obj[1];
            }

            get(updateTime, _arr =>
            {
                if (_arr != null && _arr.Length > 0)
                {
                    var add = new object[_arr.Length];
                    var addLength = 0;
                    foreach (object[] o in _arr)
                    {
                        var index = -1;
                        for (var i = 0; i < arr.Length; i++)
                            if (compare((object[])arr[i], o))
                            {
                                index = i;
                                break;
                            }

                        if (index > -1)
                        {
                            arr[index] = o;
                        }
                        else
                        {
                            add[addLength] = o;
                            addLength++;
                        }
                    }

                    var tmp = new object[arr.Length + addLength];
                    for (var i = 0; i < arr.Length; i++) tmp[i] = arr[i];
                    for (var i = 0; i < addLength; i++) tmp[i + arr.Length] = add[i];
                    arr = tmp;
                }

                if (arr.Length > 0)
                {
                    if (obj == null) obj = new object[2];
                    obj[0] = arr;
                    obj[1] = DateTools.GetNowTime();
                    SetVal(key, obj);
                }

                cb(arr);
            });
        }

        public static void GetData(string key, int time, Action<Action<JSONObject>> get, Action<JSONObject> cb)
        {
            var obj = GetJsonData(key);
            if (obj == null)
                get(_obj =>
                {
                    if (_obj != null) SetJsonData(key, time, _obj);
                    cb(_obj);
                });
            else
                cb(obj.AsObject);
        }

        public static void GetData(string key, string id, Action<int, Action<JSONArray>> get, Action<JSONArray> cb)
        {
            var obj = GetObjVal(key);
            var arr = obj["d"].AsArray;
            var updateTime = obj["t"].AsInt;
            get(updateTime, _arr =>
            {
                if (_arr != null && _arr.Count > 0)
                    foreach (JSONObject o in _arr)
                    {
                        var index = -1;
                        for (var i = 0; i < arr.Count; i++)
                            if (arr[i][id] == o[id])
                            {
                                index = i;
                                break;
                            }

                        if (index > -1)
                            arr[index] = o;
                        else
                            arr.Add(o);
                    }

                if (arr.Count > 0)
                {
                    obj["d"] = arr;
                    obj["t"] = DateTools.GetNowTime();
                    SetObjVal(key, obj);
                }

                cb(arr);
            });
        }

        public static JSONNode GetJsonData(string key)
        {
            return GetJsonData(key, DateTools.GetNowTime());
        }

        public static JSONNode GetJsonData(string key, int time)
        {
            var obj = GetObjVal(key).AsObject;
            var _time = obj["t"].AsInt;
            if (time > _time) return null;
            return obj["d"];
        }

        public static void SetJsonData(string key, int time, JSONNode node)
        {
            var obj = new JSONObject
            {
                { "d", node },
                { "t", DateTools.GetNowTime() + time }
            };
            SetObjVal(key, obj);
        }

        public static object[] GetData(string key)
        {
            return GetData(key, DateTools.GetNowTime());
        }

        public static object[] GetData(string key, int time)
        {
            var obj = GetVal(key);
            if (obj == null) return null;
            var _time = (int)obj[1];
            if (time > _time) return null;
            return (object[])obj[0];
        }

        public static void SetData(string key, int time, object[] obj)
        {
            var _obj = new object[2];
            _obj[0] = obj;
            _obj[1] = DateTools.GetNowTime() + time;
            SetVal(key, _obj);
        }

        public static void SetVal(string key, object[] value)
        {
            DataCache.SetObject(key, value);
            SaveData();
        }

        public static object[] GetVal(string key)
        {
            var obj = DataCache.GetObject(key);
            if (obj != null) return (object[])obj;
            return null;
        }

        public static JSONObject GetObjVal(string key)
        {
            return JSON.Parse(DataCache.GetString(key, "{}")).AsObject;
        }

        public static void SetObjVal(string key, JSONObject obj)
        {
            DataCache.SetString(key, obj.ToString());
            SaveData();
        }

        public static JSONArray GetArrVal(string key)
        {
            return JSON.Parse(DataCache.GetString(key, "[]")).AsArray;
        }

        public static void SetArrVal(string key, JSONArray arr)
        {
            DataCache.SetString(key, arr.ToString());
            SaveData();
        }

        public static string GetVal(string key, string d, bool player = false)
        {
            if (player)
                return PlayerCache.GetString(key, d);
            return DataCache.GetString(key, d);
        }

        public static void SetVal(string key, string value, bool player = false)
        {
            if (player)
            {
                PlayerCache.SetString(key, value);
                SavePlayer();
            }
            else
            {
                DataCache.SetString(key, value);
                SaveData();
            }
        }

        public static int GetVal(string key, int d, bool player = false)
        {
            if (player)
                return PlayerCache.GetInt(key, d);
            return DataCache.GetInt(key, d);
        }

        public static void SetVal(string key, int value, bool player = false)
        {
            if (player)
            {
                PlayerCache.SetInt(key, value);
                SavePlayer();
            }
            else
            {
                DataCache.SetInt(key, value);
                SaveData();
            }
        }

        public static float GetVal(string key, float d, bool player = false)
        {
            if (player)
                return PlayerCache.GetFloat(key, d);
            return DataCache.GetFloat(key, d);
        }

        public static void SetVal(string key, float value, bool player = false)
        {
            if (player)
            {
                PlayerCache.SetFloat(key, value);
                SavePlayer();
            }
            else
            {
                DataCache.SetFloat(key, value);
                SaveData();
            }
        }

        public static bool GetVal(string key, bool d, bool player = false)
        {
            if (player)
                return PlayerCache.GetBool(key, d);
            return DataCache.GetBool(key, d);
        }

        public static void SetVal(string key, bool value, bool player = false)
        {
            if (player)
            {
                PlayerCache.SetBool(key, value);
                SavePlayer();
            }
            else
            {
                DataCache.SetBool(key, value);
                SaveData();
            }
        }

        public static void SetPlayer(Dictionary<string, object> data)
        {
            foreach (var I in data) PlayerCache.SetObject(I.Key, I.Value);
            SavePlayer();
        }

        public static void LoadData()
        {
            DataCache.Load();
        }

        public static void LoadPlayer(string id)
        {
            PlayerCache.Load(id);
        }

        public static void SavePlayer()
        {
            PlayerCache.Save();
        }

        public static void SaveData()
        {
            DataCache.Save();
        }

        public static void SaveAll()
        {
            PlayerCache.Save();
            DataCache.Save();
        }

        public static void RemovePrefix(string prefix)
        {
            PlayerCache.DeletePrefixKey(prefix);
            DataCache.DeletePrefixKey(prefix);
            SaveAll();
        }

        public static void RemoveKey(string key)
        {
            PlayerCache.DeleteKey(key);
            DataCache.DeleteKey(key);
            SaveAll();
        }

        public static void Clear()
        {
            PlayerCache.DeleteAll();
            DataCache.DeleteAll();
            SaveAll();
        }
    }
}